import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { NzNotificationService, NzModalService, NzTreeNode, NzFormatEmitEvent } from 'ng-zorro-antd';
import { SiteService } from '@srvs/site.service';
import { ApiService } from '@srvs/api.service';

@Component({
  selector: 'menu-management',
  templateUrl: './menu-management.component.html',
  styleUrls: ['./menu-management.component.less']
})
export class MenuManagementComponent {

  public validateForm: FormGroup;
  public currentMenuNode: NzTreeNode;
  public data: any = {
    menu: []
  };
  public params: any = {
    siteId: null
  };

  constructor(
    formBuilder: FormBuilder,
    public siteSrv: SiteService,
    private modalSrv: NzModalService,
    private msgSrv: NzNotificationService,
    private apiSrv: ApiService,
  ) {
    const site: any = this.siteSrv.site || {};
    this.params.siteId = site.id;
    this.validateForm = formBuilder.group({
      menuName: [null, [Validators.required]],
      i18n: [null, [Validators.required]],
      icon: [null],
      link: [null],
      isExternal: [false],
      target: ['_self'],
      isHide: [false]
    });
    this.load();
  }

  /**
   * 请求菜单数据
   */
  public load(): void {
    const apiMenu: string = `/api/sites/${this.params.siteId}/menus`;
    this.apiSrv.get(apiMenu).subscribe(
      (menu: any[]) => {
        this.generateTreeNodes(menu);
        this.currentMenuNode = this.data.menu[0];
        this.currentMenuNode.isSelected = true;
        this.refreshFormValues(this.currentMenuNode);
      },
      error => this.msgSrv.error('菜单数据加载失败！', error.message)
    );
  }

  /**
   * 改变站点
   * @param value 站点值（公司id，站点id）
   */
  public changeSite(value: [number, number]): void {
    this.params.siteId = value[1];
    this.load();
  }

  /**
   * 收起/展开菜单目录
   * @param event 菜单节点事件对象
   */
  public toggleStatusOfMenuFolder(event: NzFormatEmitEvent): void {
    if (!event.node.isLeaf) {
      event.node.isExpanded = !event.node.isExpanded;
    }
  }

  /**
   * 收起所有菜单目录
   */
  public shrinkAllMenuFolders(): void {
    this.data.menu[0].isExpanded = false;
    this.everyMenuItem(item => item.isExpanded = false);
  }

  /**
   * 展开所有菜单目录
   */
  public expandAllMenuFolders(): void {
    this.data.menu[0].isExpanded = true;
    this.everyMenuItem(item => item.isExpanded = true);
  }

  /**
   * 选择菜单
   * @param event 菜单节点事件对象
   */
  public selectMenuItem(event: NzFormatEmitEvent): void {
    if (this.currentMenuNode !== event.node) {
      this.checkValidateForm();
      if (this.validateForm.valid) {

        // 将表单数据更新至上一选定的菜单上
        this.refreshMenuOrigin();

        // 将当前选定的菜单数据更新至表单上
        this.refreshFormValues(event.node);

        this.currentMenuNode = event.node;
      } else {
        event.node.isSelected = false;
        this.modalSrv.error({
          nzTitle: '菜单信息不合法',
          nzContent: '请完整填写菜单信息！',
        });
      }
    }

    this.currentMenuNode.isSelected = true;
  }

  /**
   * 添加子菜单目录
   * @param node 菜单节点
   * @param event 点击事件对象
   */
  public addSubMenuFolder(node: NzTreeNode, event: Event): void {
    event.stopPropagation();
    this.currentMenuNode = new NzTreeNode({
      key: Date.now().toString(),
      title: '新目录',
      menuName: '新目录',
      i18n: 'new-folder',
      siteId: this.params.siteId,
      selected: true
    });
    node.isSelected = false;
    node.addChildren([this.currentMenuNode]);
    this.refreshFormValues(this.currentMenuNode);
  }

  /**
   * 添加子菜单页面
   * @param node 菜单节点
   * @param event 点击事件对象
   */
  public addSubMenuPage(node: NzTreeNode, event: Event): void {
    event.stopPropagation();
    this.currentMenuNode = new NzTreeNode({
      key: Date.now().toString(),
      title: '新页面',
      menuName: '新页面',
      i18n: 'new-page',
      siteId: this.params.siteId,
      selected: true,
      isLeaf: true
    });
    node.isSelected = false;
    node.addChildren([this.currentMenuNode]);
    this.refreshFormValues(this.currentMenuNode);
  }

  /**
   * 删除菜单
   * @param node 菜单节点
   */
  public deleteMenuItem(node: NzTreeNode): void {
    new Promise((resolve: any, reject: any) => {
      if (!node.isLeaf && node.children.length) {
        this.modalSrv.confirm({
          nzContent: '该目录包含子菜单，删除以后子菜单会一并删除，是否继续？',
          nzMaskClosable: false,
          nzOnOk: resolve,
          nzOnCancel: reject
        });
      } else resolve();
    })
      .then(() => {

        const parentNode: NzTreeNode = node.parentNode,
          parentChildren: NzTreeNode[] = parentNode.children.filter(item => item !== node),
          index: number = parentNode.children.indexOf(node);

        parentNode.clearChildren();
        if (parentChildren.length) {
          parentNode.addChildren(parentChildren);
          this.currentMenuNode = parentNode.children[index ? index - 1 : 0];
        } else {
          this.currentMenuNode = parentNode;
        }

        this.currentMenuNode.isSelected = true;
        this.refreshFormValues(this.currentMenuNode);

      })
      .catch(() => { });
  }

  /**
   * 更新菜单数据
   */
  public refreshMenuOrigin(): void {
    const value: any = Object.assign({}, this.validateForm.value);
    if (this.currentMenuNode.level !== 2) {
      delete value.icon;
    }
    if (!this.currentMenuNode.isLeaf) {
      delete value.link;
      delete value.isExternal;
      delete value.target;
    }
    Object.assign(this.currentMenuNode.origin, value);
  }

  /**
   * 更改菜单打开方式
   */
  public changeExternal(): void {
    const value: any = this.currentMenuNode.origin;
    if (this.validateForm.get('isExternal').value) {
      this.validateForm.patchValue({
        target: value.target || '_self',
        isHide: false
      });
    } else {
      this.validateForm.patchValue({
        target: '_self',
        isHide: typeof value.isHide === 'boolean' ? value.isHide : false
      });
    }
  }

  /**
   * 验证菜单内容表单项
   * @param controlName 表单项控制器名称
   */
  public hasError(controlName: string): boolean {
    return !!(
      this.validateForm.get(controlName).dirty &&
      this.validateForm.get(controlName).errors
    );
  }

  /**
   * 保存菜单数据
   */
  public submit(): void {
    new Promise((resolve: any, reject: any) => {
      if (this.currentMenuNode.level) {
        this.checkValidateForm();
        if (this.validateForm.valid) {
          this.refreshMenuOrigin();
          resolve();
        } else reject();
      } else resolve();
    })
      .then(() => {
        const apiMenu: string = `/api/sites/${this.params.siteId}/menus`,
          menu: any[] = [];

        this.everyMenuItem(item => {
          const parentNodeIndex: string = item.parentNode.origin.nodeIndex,
            nodeIndex: number = item.parentNode.children.indexOf(item) + 1;
          item.origin.nodeIndex = parentNodeIndex
            ? `${parentNodeIndex}.${nodeIndex}`
            : nodeIndex.toString();
          menu.push(item.origin);
        });

        this.apiSrv.put(apiMenu, menu).subscribe(
          (menu: any[]) => {
            this.generateTreeNodes(menu, item => {
              if (item.origin.nodeIndex === this.currentMenuNode.origin.nodeIndex) {
                item.isSelected = true;
              }
            });
            this.msgSrv.success('保存菜单成功！', null);
          },
          error => this.msgSrv.error('保存菜单失败！', error.message)
        );
      })
      .catch(() => {
        this.modalSrv.error({
          nzTitle: '菜单信息不合法',
          nzContent: '请完整填写菜单信息！',
        });
      });
  }

  /**
   * 检查验证表单
   */
  private checkValidateForm(): void {
    for (const item in this.validateForm.controls) {
      this.validateForm.controls[item].markAsDirty();
      this.validateForm.controls[item].updateValueAndValidity();
    }
  }

  /**
   * 更新表单数据
   * @param node 菜单节点
   */
  private refreshFormValues(node: NzTreeNode): void {
    const data: any = node.origin;
    this.validateForm.patchValue({
      menuName: data.menuName,
      i18n: data.i18n,
      icon: data.icon || null,
      link: data.link || null,
      isExternal: typeof data.isExternal === 'boolean' ? data.isExternal : false,
      target: data.target || '_self',
      isHide: typeof data.isHide === 'boolean' ? data.isHide : false
    });
  }

  /**
   * 生成树形菜单
   * @param menu 平面菜单数组
   * @param each 生成每个菜单时的回调
   */
  private generateTreeNodes(menu: any[], each?: Function): void {
    const tiers: any = {},
      treeOptions: any = {
        title: 'root',
        key: 'root',
        menuName: '根目录',
        i18n: 'root',
        children: []
      };

    if (Array.isArray(menu)) {
      menu
        .map(item => {
          const treeNodeOptions: any = Object.assign({ title: item.menuName, key: item.id }, item),
            nodeIndexArr: string[] = item.nodeIndex.split('.'),
            parentNodeIndex: string = nodeIndexArr.slice(0, -1).join('.'),
            nodeIndex: string = nodeIndexArr[nodeIndexArr.length - 1];

          if (parentNodeIndex) {
            tiers[parentNodeIndex] = tiers[parentNodeIndex] || [];
            tiers[parentNodeIndex].splice(parseInt(nodeIndex), 0, treeNodeOptions);
          } else {
            treeOptions.children.splice(parseInt(nodeIndex), 0, treeNodeOptions);
          }

          return treeNodeOptions;
        })
        .forEach((item: any) => {
          if (tiers[item.nodeIndex]) {
            item.children = tiers[item.nodeIndex];
          } else {
            item.isLeaf = true;
          }

          if (typeof each === 'function') each(item);
        });
    }

    this.data.menu = [new NzTreeNode(treeOptions)];
  }

  /**
   * 遍历每个菜单
   * @param callback 遍历回调
   * @param parentAfter 父菜单后遍历
   * @param startMenu 起始菜单
   */
  private everyMenuItem(callback: Function, parentAfter?: boolean, startMenu?: NzTreeNode): void {
    startMenu = startMenu || this.data.menu[0];
    startMenu.children.forEach(item => {
      if (!parentAfter) callback(item);
      if (!item.isLeaf) this.everyMenuItem(callback, parentAfter, item);
      if (parentAfter) callback(item);
    });
  }

}
